package com.smile.file.uitl;


import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.DeleteError;
import io.minio.messages.DeleteObject;
import io.minio.messages.Item;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Component
@Configuration
@Slf4j
@RefreshScope
public class MinioUtil {

//    @Value("${minio.endpoint}")
    private String endpoint = "http://192.168.0.80:9000";

//    @Value("${minio.access-key}")
    private String accessKey = "0CCr9BQzfsn23DDuAfJ2";

//    @Value("${minio.secret-key}")
    private String secretKey = "Afx1t2DDKG89WcLVLfwsvKQ8AcpH64SU6gvE8rak";

//    @Value("${minio.bucket-name}")
    private String defaultBucketName = "my-bucket";


//    //    @Value("${minio.endpoint}")
//    private String endpoint = "http://111.62.188.29:9000";
//
//    //    @Value("${minio.access-key}")
//    private String accessKey = "uiBUo0dIis3DE0DbyXJI";
//
//    //    @Value("${minio.secret-key}")
//    private String secretKey = "b9O0Pzdg0J04dG55MEgxUyTiIJCiKY2u6F3wvhyj";
//
//    //    @Value("${minio.bucket-name}")
//    private String defaultBucketName = "my-bucket";




    public MinioClient minioClient() {
        return MinioClient.builder()
                .endpoint(endpoint)
                .credentials(accessKey, secretKey)
                .build();
    }

    /**
     * 检查存储桶是否存在
     *
     * @param bucketName 存储桶名称
     * @return 是否存在
     */
    @SneakyThrows
    public boolean bucketExists(String bucketName) {
        return minioClient().bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
    }

    /**
     * 创建存储桶
     *
     * @param bucketName 存储桶名称
     */
    @SneakyThrows
    public void makeBucket(String bucketName) {
        if (!bucketExists(bucketName)) {
            minioClient().makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
        }
    }

    /**
     * 获取所有存储桶
     *
     * @return 存储桶列表
     */
    @SneakyThrows
    public List<Bucket> listBuckets() {
        return minioClient().listBuckets();
    }

    /**
     * 删除存储桶
     *
     * @param bucketName 存储桶名称
     */
    @SneakyThrows
    public void removeBucket(String bucketName) {
        minioClient().removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
    }

    /**
     * 简单文件上传
     *
     * @param file       文件
     * @param bucketName 存储桶名称
     * @return 文件信息
     */
    @SneakyThrows
    public Map<String, Object> uploadFile(MultipartFile file, String bucketName,String dir) {
        if (file == null || file.isEmpty()) {
            return null;
        }

        if (!bucketExists(bucketName)) {
            makeBucket(bucketName);
        }

        String originalFilename = file.getOriginalFilename();
        String fileName = UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));

        minioClient().putObject(PutObjectArgs.builder()
                .bucket(bucketName)
                .object(dir+"/"+fileName)
//                .contentType(file.getContentType())
                .stream(file.getInputStream(), file.getSize(), -1)
                .build());

        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("fileName", fileName);
        resultMap.put("originalFilename", originalFilename);
        resultMap.put("url", getObjectUrl(bucketName, dir+"/"+fileName, 7));

        return resultMap;
    }
    /**
     * 简单文件上传
     *
     * @param file       文件
     * @param bucketName 存储桶名称
     * @return 文件信息
     */
    @SneakyThrows
    public Map<String, String> uploadFile(MultipartFile file, String bucketName) {
        if (file == null || file.isEmpty()) {
            return null;
        }

        if (!bucketExists(bucketName)) {
            makeBucket(bucketName);
        }

        String originalFilename = file.getOriginalFilename();
        String fileName = UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));

        minioClient().putObject(PutObjectArgs.builder()
                .bucket(bucketName)
                .object(fileName)
                .contentType(file.getContentType())
                .stream(file.getInputStream(), file.getSize(), -1)
                .build());

        Map<String, String> resultMap = new HashMap<>();
        resultMap.put("fileName", fileName);
        resultMap.put("originalFilename", originalFilename);
        resultMap.put("url", getObjectUrl(bucketName, fileName, 7));

        return resultMap;
    }
    /**
     * 简单文件上传（使用默认存储桶）
     *
     * @param file 文件
     * @return 文件信息
     */
    public Map<String, String> uploadFile(MultipartFile file) {
        return uploadFile(file, defaultBucketName);
    }

    /**
     * 简单文件上传（使用默认存储桶）
     *
     * @param file 文件
     * @return 文件信息
     */
    public Map<String, Object> uploadFile2(MultipartFile file,String dir) {
        return uploadFile(file, defaultBucketName,dir);
    }


    /**
     * 批量文件上传
     *
     * @param files      文件列表
     * @param bucketName 存储桶名称
     * @return 文件信息列表
     */
    public List<Map<String, String>> uploadFiles(List<MultipartFile> files, String bucketName) {
        return files.stream()
                .map(file -> uploadFile(file, bucketName))
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }

    /**
     * 批量文件上传（使用默认存储桶）
     *
     * @param files 文件列表
     * @return 文件信息列表
     */
    public List<Map<String, String>> uploadFiles(List<MultipartFile> files) {
        return uploadFiles(files, defaultBucketName);
    }

    /**
     * 下载文件
     *
     * @param bucketName 存储桶名称
     * @param objectName 对象名称
     * @return 输入流
     */
    @SneakyThrows
    public InputStream downloadFile(String bucketName, String objectName) {
        return minioClient().getObject(GetObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .build());
    }

    /**
     * 下载文件（使用默认存储桶）
     *
     * @param objectName 对象名称
     * @return 输入流
     */
    public InputStream downloadFile(String objectName) {
        return downloadFile(defaultBucketName, objectName);
    }

    /**
     * 删除文件
     *
     * @param bucketName 存储桶名称
     * @param objectName 对象名称
     */
    @SneakyThrows
    public void deleteFile(String bucketName, String objectName) {
        minioClient().removeObject(RemoveObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .build());
    }

    /**
     * 删除文件（使用默认存储桶）
     *
     * @param objectName 对象名称
     */
    public void deleteFile(String objectName) {
        deleteFile(defaultBucketName, objectName);
    }

    /**
     * 批量删除文件
     *
     * @param bucketName  存储桶名称
     * @param objectNames 对象名称列表
     * @return 删除错误列表
     */
    @SneakyThrows
    public List<DeleteError> deleteFiles(String bucketName, List<String> objectNames) {
        List<DeleteObject> objects = objectNames.stream()
                .map(DeleteObject::new)
                .collect(Collectors.toList());

        Iterable<Result<DeleteError>> results = minioClient().removeObjects(RemoveObjectsArgs.builder()
                .bucket(bucketName)
                .objects(objects)
                .build());

        List<DeleteError> errors = new ArrayList<>();
        for (Result<DeleteError> result : results) {
            errors.add(result.get());
        }
        return errors;
    }

    /**
     * 批量删除文件（使用默认存储桶）
     *
     * @param objectNames 对象名称列表
     * @return 删除错误列表
     */
    public List<DeleteError> deleteFiles(List<String> objectNames) {
        return deleteFiles(defaultBucketName, objectNames);
    }

    /**
     * 获取文件URL
     *
     * @param bucketName 存储桶名称
     * @param objectName 对象名称
     * @param expires    过期时间（天）
     * @return 文件URL
     */
    @SneakyThrows
    public String getObjectUrl(String bucketName, String objectName, int expires) {
        return minioClient().getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                .method(Method.GET)
                .bucket(bucketName)
                .object(objectName)
                .expiry(expires, TimeUnit.DAYS)
                .build());
    }

    /**
     * 获取文件URL（使用默认存储桶）
     *
     * @param objectName 对象名称
     * @param expires    过期时间（天）
     * @return 文件URL
     */
    public String getObjectUrl(String objectName, int expires) {
        return getObjectUrl(defaultBucketName, objectName, expires);
    }

    /**
     * 检查文件是否存在
     *
     * @param bucketName 存储桶名称
     * @param objectName 对象名称
     * @return 是否存在
     */
    @SneakyThrows
    public boolean objectExists(String bucketName, String objectName) {
        try {
            minioClient().statObject(StatObjectArgs.builder()
                    .bucket(bucketName)
                    .object(objectName)
                    .build());
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 检查文件是否存在（使用默认存储桶）
     *
     * @param objectName 对象名称
     * @return 是否存在
     */
    public boolean objectExists(String objectName) {
        return objectExists(defaultBucketName, objectName);
    }

    /**
     * 列出存储桶中的所有对象
     *
     * @param bucketName 存储桶名称
     * @return 对象列表
     */
    @SneakyThrows
    public List<Item> listObjects(String bucketName) {
        Iterable<Result<Item>> results = minioClient().listObjects(ListObjectsArgs.builder()
                .bucket(bucketName)
                .build());

        List<Item> items = new ArrayList<>();
        for (Result<Item> result : results) {
            items.add(result.get());
        }
        return items;
    }

    /**
     * 列出存储桶中的所有对象（使用默认存储桶）
     *
     * @return 对象列表
     */
    public List<Item> listObjects() {
        return listObjects(defaultBucketName);
    }

//    /**
//     * 创建分片上传
//     *
//     * @param bucketName 存储桶名称
//     * @param objectName 对象名称
//     * @return 上传ID
//     */
//    @SneakyThrows
//    public String createMultipartUpload(String bucketName, String objectName) {
//        CreateMultipartUploadResponse response = minioClient().createMultipartUpload(CreateMultipartUploadArgs.builder()
//                .bucket(bucketName)
//                .object(objectName)
//                .build());
//        return response.result().uploadId();
//    }
//
//    /**
//     * 上传分片
//     *
//     * @param bucketName 存储桶名称
//     * @param objectName 对象名称
//     * @param uploadId   上传ID
//     * @param partNumber 分片编号
//     * @param stream     输入流
//     * @param size       大小
//     * @return 分片ETag
//     */
//    @SneakyThrows
//    public String uploadPart(String bucketName, String objectName, String uploadId, int partNumber, InputStream stream, long size) {
//        UploadPartResponse response = minioClient.uploadPart(UploadPartArgs.builder()
//                .bucket(bucketName)
//                .object(objectName)
//                .uploadId(uploadId)
//                .partNumber(partNumber)
//                .stream(stream, size, -1)
//                .build());
//        return response.etag();
//    }
//
//    /**
//     * 完成分片上传
//     *
//     * @param bucketName 存储桶名称
//     * @param objectName 对象名称
//     * @param uploadId   上传ID
//     * @param etags      分片ETag列表
//     */
//    @SneakyThrows
//    public void completeMultipartUpload(String bucketName, String objectName, String uploadId, List<String> etags) {
//        List<CompletePart> completeParts = new ArrayList<>();
//        for (int i = 0; i < etags.size(); i++) {
//            completeParts.add(new CompletePart(i + 1, etags.get(i)));
//        }
//
//        minioClient.completeMultipartUpload(CompleteMultipartUploadArgs.builder()
//                .bucket(bucketName)
//                .object(objectName)
//                .uploadId(uploadId)
//                .parts(completeParts)
//                .build());
//    }

    /**
     * 生成文件哈希值（用于秒传判断）
     *
     * @param file 文件
     * @return 哈希值
     */
    @SneakyThrows
    public String generateFileHash(MultipartFile file) {
        // 这里使用简单的文件大小和修改时间作为哈希值，实际应用中应使用MD5或SHA-1等算法
        return file.getSize() + "-" + file.getOriginalFilename();
    }
}